package ru.hh.team02.chat.utils;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class StringSocket {
    private final Socket socket;
    
    private ObjectInputStream in;
    private ObjectOutputStream out;

    /**
     * Whapper for a socket which opens streams and handles their closing along with the socket.
     * @param socket Socket to wrap.
     */
    public StringSocket(Socket socket) {
        this.socket = socket;
        try {
            openStreams();
        } catch (IOException e) {
            // XXX [Oleg] Logger?
            e.printStackTrace();
        }
    }

    /**
     * Read from socket
     * @return read string
     * @throws IOException
     */
    public String read() throws IOException {
        try {
            return (String)in.readObject();
        } catch (ClassNotFoundException e) {
            // XXX [Oleg] Shouldn't we log this carefully?
            // I think it should rethrow exception and don't just return "".
            e.printStackTrace();
        }
        return "";
    }

    /**
     * Write to socket
     * @return string to write
     * @throws IOException
     */
    public void write(String message) throws IOException {
        // XXX [Oleg] What about exceptions? It throws them? I think we should rethrow.
        out.writeObject(message);
        out.flush();
    }

    /**
     * Is there any data available in the input socket stream.
     * @throws IOException
     */
    public boolean available() throws IOException {
        return socket.getInputStream().available() > 0;
    }

    /**
     * Close in and out streams and the socket.
     */
    // XXX [Oleg] What if out is none and in is none. It may be so if close is called before opening streams.
    public void close() {     
        try {
            out.close();
        } catch (IOException ioException1) {
            // XXX [Oleg] We love loggers!
            ioException1.printStackTrace();
        } finally {
            try {
                in.close();
            } catch(IOException ioException2) {
                // XXX [Oleg] We definitely love them!
                ioException2.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e3) {
                    // XXX [Oleg] Loggers are in our dreams!
                    e3.printStackTrace();
                }
            }
        }
    }

    /**
     * Open streams
     * @throws IOException
     */
    // XXX [Oleg] What if we accidentally call this method twice? I would rather have it in the constructor.
    private void openStreams() throws IOException {
        out = new ObjectOutputStream(socket.getOutputStream());
        // XXX [Oleg] Why do we need flush here?
        out.flush();
        in = new ObjectInputStream(socket.getInputStream());
    }
    
}